<template>
  <div :class="['mindMap', isFullScreen ? 'phase-fullScreen' : '']">
    <!-- 控制面板 -->
    <div class="edit-panel">
      <div class="operate-btn">
        <div v-for="item in controlItems">
          <el-button style=" border-radius: 10px;"
            @click="item.action" :disabled="item.disabledCondition" v-if="item.isShow">
            <div class="item-menu">
              <el-icon v-if="item.iconType === 'el-icon'" size="18px">
                <component :is="item.icon" />
              </el-icon>
              <span>{{ item.text }}</span>
            </div>
          </el-button>
        </div>
      </div>
    </div>

    <div class="chart-mindMap">
      <div class="canvas-container" ref="canvasContainerRef" @contextmenu="showContextMenu('add', '', $event)" @mousedown="handleCanvasMouseDown">
        <svg ref="svgRef" @click="handleSvgClick" class="svg-box">
          <!-- 定义箭头标记 -->
          <defs>
            <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
              <polygon points="0 0, 10 3.5, 0 7" fill="#666" />
            </marker>
            <marker id="arrowhead-selected" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
              <polygon points="0 0, 10 3.5, 0 7" fill="#666" />
            </marker>
          </defs>

          <!-- 连接线 -->
          <path v-for="(connection, index) in visibleConnections" :key="index" :d="connection.path" class="connection"
            :class="{ selected: selectedConnection === connection }" :stroke="connection.selected ? '#a0cfff' : '#666'"
            :stroke-width="2" fill="none"
            :marker-end="connection.selected ? 'url(#arrowhead-selected)' : 'url(#arrowhead)'"
            @click="selectConnection(connection)" @contextmenu.stop="showContextMenu('path', connection, $event)" />

          <!-- 节点连接点 -->
          <circle v-for="controlPoint in nodeControlPoints" :key="controlPoint.pointId" :cx="controlPoint.x"
            :cy="controlPoint.y" r="7" fill="#a0cfff" class="control-point"
            @mousedown="startConnectionFromPoint(controlPoint)" @click.stop />

          <!-- 框选区域矩形 -->
          <rect v-if="selectionBox.visible" :x="selectionBox.startX" :y="selectionBox.startY"
            :width="selectionBox.width" :height="selectionBox.height" class="selection-box"
            fill="rgba(64, 158, 255, 0.1)" stroke="#409eff" stroke-width="1" stroke-dasharray="5,5" />
        </svg>
        <!-- 节点 -->
        <div v-for="node in visibleNodes" :key="node.nodeId"
          :class="['node', dragActiveNode?.nodeId === node.nodeId ? 'dragActiveNode' : '']"
          :ref="(el) => setNodeRef(el, node.nodeId)" :style="{
            left: node.x + 'px',
            top: node.y + 'px',
            minWidth: nodeMinWidth + 'px',
            minHeight: nodeMinHeight + 'px',
            background: node.style.bgColor,
            borderStyle: 'solid',
            borderWidth: node.style.borderWeight + 'px',
            borderColor: node.style.borderColor,
            boxShadow: `0 0 3px 1px ${selectedNode?.nodeId === node.nodeId || selectionBox.selectedNodes.map(item => item.nodeId).includes(node.nodeId) ? node.style.borderColor : '#ffffff00'}`,
          }" :data-node-id="node.nodeId" @contextmenu.stop="showContextMenu('node', node, $event)"
          @mousedown="handleNodeMouseDown(node, $event)" @dblclick="handleNodeDoubleClick(node, $event)">
          <div class="node-main" @mousedown="handleNodeMouseDown(node, $event)" :style="{
            fontSize: node.style.fontSize + 'px',
            fontWeight: node.style.fontWeight,
            color: node.style.fontColor
          }">
            <div class="node-text">{{ node.name }}</div>
          </div>
          <div v-if="isNodeCollapsed(node) && getCollapsedNodeCount(node, treeData) > 0" class="collapsed-count" :style="{
            color: node.style.fontColor,
            borderColor: node.style.borderColor,
          }">
            {{ getCollapsedNodeCount(node, treeData) }}
          </div>
        </div>

        <!-- 右键菜单 -->
        <div v-if="contextMenu.visible" class="context-menu"
          :style="{ left: contextMenu.x + 'px', top: contextMenu.y + 'px' }">
          <div v-if="contextMenu.menuType === 'node' && isEditMode">
            <div class="context-menu-item" @click="addNodeFromContextMenu">添加节点</div>
            <div class="context-menu-item" @click="editNodeFromContextMenu">修改内容</div>
            <div class="context-menu-item" @click="removeNodeFromContextMenu"
              :class="{ disabled: selectedNode && selectedNode.level === 0 }">删除节点</div>
          </div>

          <div v-else-if="contextMenu.menuType === 'path' && isEditMode">
            <div class="context-menu-item" @click="removeSelectedConnection">删除连线</div>
            <div class="context-menu-item" @click=" contextMenu.otherMenu = !contextMenu.otherMenu">
              修改方向
              <div class="context-menu-item-direction" v-if="contextMenu.otherMenu">
                <div class="context-menu-item" @click="toggleConnectionDirection(DirectionEnum.HOR)"
                  :class="{ disabled: selectedConnection.pathDirection === DirectionEnum.HOR }">水平方向</div>
                <div class="context-menu-item" @click="toggleConnectionDirection(DirectionEnum.VER)"
                  :class="{ disabled: selectedConnection.pathDirection === DirectionEnum.VER }">垂直方向</div>
              </div>
            </div>
          </div>

          <div v-else-if="contextMenu.menuType === 'add' && isEditMode">
            <div class="context-menu-item" @click="addNodeFromContextMenu"
              :class="{ disabled: treeData.length === 0 }">添加节点</div>
          </div>

          <div v-if="contextMenu.menuType === 'node'" class="context-menu-item"
            @click="toggleNodeCollapseFromContextMenu">
            {{ isNodeCollapsed(selectedNode) ? '展开节点' : "折叠节点" }}
          </div>
        </div>

        <!-- 节点编辑器 -->
        <div v-if="contextEditor.visible" class="context-editor"
          :style="{ left: contextEditor.x + 'px', top: contextEditor.y + 'px' }">
          <el-input ref="textInput" v-model="contextEditor.editingNodeContent" type="textarea" resize="none"
            :autosize="{ minRows: 2, maxRows: 4 }" placeholder="输入节点内容（支持HTML）" />
          <div style="margin-top: 10px">
            <el-button @click="saveNodeContent" type="primary">保存</el-button>
            <el-button @click="hideEditor">取消</el-button>
          </div>
        </div>
      </div>
      <div v-if="!drawer">
        <diagramNodeDetail ref="detailRef" :selectedNode="selectedNode" @updateNodeStyle="updateNodeStyleEvent" />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, computed, nextTick } from 'vue'
import { ElMessage } from 'element-plus';
import { SetUp, Edit,  Pointer, CirclePlusFilled, RefreshRight, DataBoard, FullScreen, Document } from '@element-plus/icons-vue'
import { v4 as uuidv4 } from 'uuid';
import diagramNodeDetail from '../DiagramNodeDetail/index.vue'
import {  getCollapsedNodeCount } from './handleDataStructure'
const NODE_STYLE = {
  bgColor: '#ffffff',
  borderColor: '#3498db',
  borderWeight: 2,
  fontColor: '#3498db',
  fontWeight: 400,
  fontSize: 14,
}

const DirectionEnum = {
  VER: 'vertical', /** 垂直 */
  HOR: 'horizontal', /** 水平 */
  AUTO: 'auto', /** 自适应 */
};

const fakeData = [
  {
    "nodeId": "ff65e03c-35ac-426c-942c-e3fa018d86dd",
    "level": 0,
    "preIds": [],
    "nextIds": [
      "2d5b260c-ffb0-474e-877e-d079baa50e62"
    ],
    "name": "根节点",
    "x": 221.0593105294497,
    "y": 71.73256949492338,
    "style": {
      "bgColor": "#ffffff",
      "borderColor": "#3498db",
      "borderWeight": 2,
      "fontColor": "#3498db",
      "fontWeight": 400,
      "fontSize": 14
    }
  },
  {
    "nodeId": "2d5b260c-ffb0-474e-877e-d079baa50e62",
    "level": 1,
    "preIds": [
      "ff65e03c-35ac-426c-942c-e3fa018d86dd"
    ],
    "nextIds": [],
    "name": "子节点1",
    "x": 368.1712023772042,
    "y": 189.73256949492338,
    "style": {
      "bgColor": "#ffffff",
      "borderColor": "#3498db",
      "borderWeight": 2,
      "fontColor": "#3498db",
      "fontWeight": 400,
      "fontSize": 14
    }
  }
]

// 节点最小宽高
const nodeMinWidth = 140
const nodeMinHeight = 45

// 树形结构数据
let oldData = []  // 最开始从接口获取的数据，坐标没变，用户保存时还原坐标
const treeData = ref([]);  // 坐标改变后的数据
const connectionPositions = ref(new Map()); // 存储连接线位置信息

const selectedNode = ref(null);  // 选中的节点
const selectedConnection = ref(null);  // 选中的连接线
const connectionSource = ref(null);  // 选中连接节点

const isEditMode = ref(false); // 编辑模式状态
const isFullScreen = ref(false); // 全屏状态

// 框选相关状态
const selectionBox = ref({
  visible: false,
  selectedNodes: [],
  startX: 0,
  startY: 0,
  endX: 0,
  endY: 0,
  width: 0,
  height: 0
});

// 节点折叠状态管理
const collapsedNodes = ref(new Set()); // 存储被折叠的节点ID
// 节点拖拽相关变量
const nodeDrag = ref({
  isDragging: false,   // 拖拽标志
  dragStartX: 0,       // 拖拽x
  dragStartY: 0,       // 拖拽Y
  initialNodeX: 0,     // 拖拽节点初始x
  initialNodeY: 0,     // 拖拽节点初始Y
})

// 右键菜单
const contextMenu = ref({
  visible: false,
  x: 0,
  y: 0,
  node: null,
  otherMenu: false,
  menuType: 'node'
});
// 编辑器
const contextEditor = ref({
  visible: false,
  x: 0,
  y: 0,
  editingNodeContent: '',
  node: null,
})

const svgRef = ref(null);
const canvasContainerRef = ref(null);
const textInput = ref();
// 节点Ref
const nodeRefs = ref(new Map());
const setNodeRef = (el, nodeId) => {
  if (el) {
    nodeRefs.value.set(nodeId, el);
  }
};

// 定义按钮数组
const controlItems = computed(() => [
  {icon: Edit,iconType: 'el-icon',text: isEditMode.value ? '退出编辑模式' : '进入编辑模式',action: () => toggleEditMode,isShow: true},
  {icon: CirclePlusFilled,iconType: 'el-icon', text: '添加节点',action: () => addNode(0, 0),disabledCondition: !isEditMode.value,isShow: isEditMode.value},
  {icon: DataBoard,iconType: 'el-icon',text: '概要',action: () => handleProfile(),disabledCondition: selectionBox.value.selectedNodes.length === 0,isShow: true},
  {icon: Pointer,iconType: 'el-icon',text: '存储',action: () => saveData(),disabledCondition: treeData.value.length === 0,isShow: true},
  {icon: RefreshRight,iconType: 'el-icon',text: '重置',action: () => reshData(),isShow: true},
  {icon: SetUp,iconType: 'el-icon',text: '格式',action: () => handleChange(),isShow: true},
  {icon: FullScreen,iconType: 'el-icon',text: '全屏',action: () => { isFullScreen.value = !isFullScreen.value },isShow: true},
])

// 可见节点计算（考虑折叠状态）
const visibleNodes = computed(() => {
  return treeData.value.filter(node => {
    // 检查节点的所有祖先节点是否都被展开
    return isNodeVisible(node);
  });
});

// 可见连接线计算（仅显示连接可见节点的线）
const visibleConnections = computed(() => {
  return connections.value.filter(conn => {
    const parent = treeData.value.find(n => n.nodeId === conn.parentId);
    const child = treeData.value.find(n => n.nodeId === conn.childId);
    return parent && child && isNodeVisible(parent) && isNodeVisible(child);
  });
});

// 检查节点是否可见（所有祖先节点都未被折叠）
const isNodeVisible = (node) => {
  // 根节点总是可见
  if (!node.preIds || node.preIds.length === 0) {
    return true;
  }

  // 检查所有祖先节点是否被折叠
  for (const parentId of node.preIds) {
    if (collapsedNodes.value.has(parentId)) {
      return false;
    }

    // 递归检查祖先节点的可见性
    const parent = treeData.value.find(n => n.nodeId === parentId);
    if (parent && !isNodeVisible(parent)) {
      return false;
    }
  }

  return true;
};

// 检查节点是否被折叠
const isNodeCollapsed = (node) => {
  return node && collapsedNodes.value.has(node.nodeId);
};

// 节点控制点（连接点）
const nodeControlPoints = computed(() => {
  const points = [];
  if (!isEditMode.value) return points // 非编辑模式下不显示连接点
  visibleNodes.value.forEach(node => {
    // 获取节点实际尺寸，如果无法获取则使用最小宽度和高度
    const { nodeActualWidth, nodeActualHeight } = getActualData(node)
    const halfWidth = nodeActualWidth / 2;
    const halfHeight = nodeActualHeight / 2;
    const connectionPoints = [
      { position: 'top', x: halfWidth, y: 0 },
      { position: 'bottom', x: halfWidth, y: nodeActualHeight },
      { position: 'left', x: 0, y: halfHeight },
      { position: 'right', x: nodeActualWidth, y: halfHeight }
    ];
    connectionPoints.forEach(({ position, x, y }) => {
      points.push({
        pointId: `${node.nodeId}-${position}`,
        nodeId: node.nodeId,
        x: node.x + x,
        y: node.y + y,
        position
      });
    });
  });
  return points;
});

// 连接线数据
const connections = computed(() => {
  const conns = [];
  treeData.value.forEach(childNode => {
    if (!childNode.preIds || childNode.preIds.length === 0) return
    childNode.preIds.forEach(parentId => {
      const parentNode = treeData.value.find(node => node.nodeId === parentId);
      if (!parentNode) return
      const { nodeActualWidth: parentWidth, nodeActualHeight: parentHeight } = getActualData(parentNode);
      const parentCenterX = parentNode.x + parentWidth / 2;
      const parentCenterY = parentNode.y + parentHeight / 2;

      const { nodeActualWidth: childWidth, nodeActualHeight: childHeight } = getActualData(childNode);
      const childCenterX = childNode.x + childWidth / 2;
      const childCenterY = childNode.y + childHeight / 2;

      // 计算父节点和子节点的相对位置
      const deltaX = childCenterX - parentCenterX;
      const deltaY = childCenterY - parentCenterY;

      // 特殊处理：当节点几乎在同一水平线上时，使用水平方向连接
      const isAlmostHorizontal = Math.abs(deltaY) < nodeMinHeight; // 阈值

      // 检查是否有用户自定义的方向偏好
      const directionKey = `${parentNode.nodeId}-${childNode.nodeId}-direction`;
      const userDirection = connectionPositions.value.get(directionKey);

      // 获取连接点信息
      const startPoint = getConnectionPoint(parentNode, deltaX, deltaY, true, userDirection);
      const endPoint = getConnectionPoint(childNode, deltaX, deltaY, false, userDirection);

      // 获取自定义中间点位置或计算默认位置
      const midX = connectionPositions.value.get(`${parentNode.nodeId}-${childNode.nodeId}-midX`) ||
        (startPoint.isHorizontalFirst || isAlmostHorizontal ? (startPoint.x + endPoint.x) / 2 : startPoint.x);

      const midY = connectionPositions.value.get(`${parentNode.nodeId}-${childNode.nodeId}-midY`) ||
        (startPoint.isHorizontalFirst || isAlmostHorizontal ? startPoint.y : (startPoint.y + endPoint.y) / 2);

      let path;
      let pathDirection;
      // 水平方向优先，先水平再垂直
      if (startPoint.isHorizontalFirst || isAlmostHorizontal) {
        path = `M ${startPoint.x} ${startPoint.y} L ${midX} ${startPoint.y} L ${midX} ${endPoint.y} L ${endPoint.x} ${endPoint.y}`;
        pathDirection = DirectionEnum.HOR
      }
      // 垂直方向优先，先垂直再水平
      else {
        path = `M ${startPoint.x} ${startPoint.y} L ${startPoint.x} ${midY} L ${endPoint.x} ${midY} L ${endPoint.x} ${endPoint.y}`;
        pathDirection = DirectionEnum.VER
      }

      // 添加连接线
      conns.push({
        path: path,
        pathDirection: pathDirection,
        manual: false,
        parentId: parentNode.nodeId,
        childId: childNode.nodeId,
        type: 'branch',
        pathId: `${parentNode.nodeId}-${childNode.nodeId}-branch`,
        startPoint: startPoint,
        endPoint: endPoint
      });

    });
  });
  return conns;
});

/**
 * 根据方向确定连接点位置
 * @param node 节点
 * @param deltaX 相对于目标节点的X差值
 * @param deltaY 相对于目标节点的Y差值
 * @param isStartPoint 是否为起点（父节点）
 * @param userDirection 用户自定义方向
 * @returns 连接点坐标和方向信息
 */
const getConnectionPoint = (node, deltaX, deltaY, isStartPoint, userDirection) => {
  const { nodeActualWidth, nodeActualHeight } = getActualData(node);

  // 判断主要方向
  const isHorizontal = Math.abs(deltaX) >= Math.abs(deltaY);
  const isRight = deltaX > 0;
  const isDown = deltaY > 0;

  // 特殊处理：当节点几乎在同一水平线上时，使用水平方向连接
  const isAlmostHorizontal = Math.abs(deltaY) < nodeMinHeight; // 阈值

  // 根据节点类型（起点/终点）和方向确定连接点
  let x, y;
  if (isStartPoint) {
    // 起点（父节点）的连接点
    if (userDirection === DirectionEnum.HOR || isAlmostHorizontal) {
      // 水平方向优先，起点连接右边或左边
      x = isRight ? node.x + nodeActualWidth : node.x;
      y = node.y + nodeActualHeight / 2;
    } else {
      // 垂直方向优先，起点连接下边或上边
      x = node.x + nodeActualWidth / 2;
      y = isDown ? node.y + nodeActualHeight : node.y;
    }
  } else {
    // 终点（子节点）的连接点
    if (userDirection === DirectionEnum.HOR || isAlmostHorizontal) {
      // 水平方向优先，终点连接左边或右边
      x = isRight ? node.x : node.x + nodeActualWidth;
      y = node.y + nodeActualHeight / 2;
    } else {
      // 垂直方向优先，终点连接上边或下边
      x = node.x + nodeActualWidth / 2;
      y = isDown ? node.y : node.y + nodeActualHeight;
    }
  }

  return {
    x,
    y,
    isHorizontalFirst: userDirection === DirectionEnum.HOR || isAlmostHorizontal,
    isRight,
    isDown,
    isHorizontal
  };
}

/**
 * 获取元素实际信息
 * @param node 节点
 */
const getActualData = (node) => {
  let nodeActualWidth = nodeMinWidth;
  let nodeActualHeight = nodeMinHeight
  const nodeRef = nodeRefs.value.get(node.nodeId);
  if (nodeRef) {
    nodeActualWidth = Math.max(nodeRef.offsetWidth || nodeMinWidth, nodeActualWidth);
    nodeActualHeight = Math.max(nodeRef.offsetHeight || nodeMinHeight, nodeActualHeight);
  }
  return {
    nodeActualWidth, nodeActualHeight
  }
}

/**
 * 获取鼠标在画布容器内的坐标
 * @param {MouseEvent} event 鼠标事件
 * @returns {Object} 包含x和y坐标的对象
 */
const getMousePositionInCanvas = (event) => {
  if (!canvasContainerRef.value) return { x: 0, y: 0 };
  const containerRect = canvasContainerRef.value.getBoundingClientRect();
  const x = event.clientX - containerRect.left + canvasContainerRef.value.scrollLeft;
  const y = event.clientY - containerRect.top + canvasContainerRef.value.scrollTop;
  return { x, y };
}

// 创建新节点
const addNode = (addNodeX, addNodeY) => {
  if (!isEditMode.value) return;
  clearSelectionBox()
  // 如果有选中节点，则添加为子节点
  if (selectedNode.value) {
    const parentNode = selectedNode.value;
    // 计算新节点的位置
    let x, y;
    const { nodeActualWidth: parentWidth } = getActualData(parentNode);
    x = parentNode.x + parentWidth + Math.random() * 300;
    y = parentNode.y + 100;

    const newNode = {
      nodeId: uuidv4(),
      level: parentNode.level + 1,
      preIds: [parentNode.nodeId],
      nextIds: [],
      name: `子节点`,
      x: x,
      y: y,
      style: NODE_STYLE
    };

    treeData.value.push(newNode);
    if (!parentNode.nextIds.includes(newNode.nodeId)) {
      parentNode.nextIds.push(newNode.nodeId);
    }
    selectedNode.value = newNode;
  } else {
    // 如果没有选中节点，创建一个独立节点
    const newNode = {
      nodeId: uuidv4(),
      level: 0,
      preIds: [],
      nextIds: [],
      name: `子节点`,
      x: addNodeX ? addNodeX : 400 + Math.random() * 200,
      y: addNodeY ? addNodeY : 100 + Math.random() * 300,
      style: NODE_STYLE
    };
    treeData.value.push(newNode);
    selectedNode.value = newNode;
  }
}

// 从上下文菜单添加节点
const addNodeFromContextMenu = (event) => {
  console.log('event',event);
  
  hideAllMenu()
  const { x, y } = getMousePositionInCanvas(event);
  console.log('x, y',x, y);
  
  addNode(x, y);
}

// 节点删除
const removeSelectedNode = () => {
  if (!isEditMode.value) return;
  if (!selectedNode.value || selectedNode.value.nodeId === 1) return
  const nodeId = selectedNode.value.nodeId;
  removeNodeAndChildren(nodeId)
}

/**
 * 删除该节点及其所有子节点
 * @param nodeId 节点id
 */
const removeNodeAndChildren = async (nodeId) => {
  const nodeToRemove = treeData.value.find(node => node.nodeId === nodeId);
  if (!nodeToRemove) return;
  // 判断是否有子节点
  if (nodeToRemove.nextIds.length > 0) {
    ElMessage({
      message: '请先删除子节点',
      type: 'warning',
    })
    return;
  }

  // 递归删除所有子节点
  if (nodeToRemove.nextIds && nodeToRemove.nextIds.length > 0) {
    // 创建子节点ID副本，因为在递归过程中会修改nextUuIds数组
    const childrenIds = [...nodeToRemove.nextIds];
    childrenIds.forEach(async childId => {
      await removeNodeAndChildren(childId);
    });
  }

  // 从所有父节点的nextUuIds中移除该节点
  if (nodeToRemove.preIds && nodeToRemove.preIds.length > 0) {
    nodeToRemove.preIds.forEach(parentId => {
      const parentNode = treeData.value.find(node => node.nodeId === parentId);
      if (parentNode && parentNode.nextIds) {
        const childIndex = parentNode.nextIds.indexOf(nodeId);
        if (childIndex !== -1) {
          parentNode.nextIds.splice(childIndex, 1);
        }
      }
    });
  }
  // 从treeData中移除该节点
  treeData.value = treeData.value.filter(item => item.nodeId !== nodeId);
}

/**
 * 开始连接点 
 * @param controlPoint 连接点信息
 */
const startConnectionFromPoint = (controlPoint) => {
  if (!isEditMode.value) return;
  const node = treeData.value.find(n => n.nodeId === controlPoint.nodeId);
  if (!node) return;

  // 选择第一个节点
  if (!connectionSource.value) {
    connectionSource.value = node;
    selectedNode.value = node;
  }
  // 选择第二个节点，创建连接
  else {
    if (connectionSource.value.nodeId !== node.nodeId) {
      // 检查是否已存在连接
      let connectionExists = false;

      // 检查是否已经有父子关系
      if (node.preIds && Array.isArray(node.preIds)) {
        connectionExists = node.preIds.includes(connectionSource.value.nodeId);
      }

      // 修改数据之间的父子关系
      if (!connectionExists) {
        // 将connectionSource作为父节点，node作为子节点
        addChildNodeToParent(node, connectionSource.value, 'connectLine');
      }
    }

    // 重置连接模式
    connectionSource.value = null;
    selectedNode.value = null;
  }
}

/**
 * 将子节点添加到新父节点
 * @param childNode 子节点
 * @param parentNode 父节点
 * @param addType  drag-通过拖拽添加  connectLine-通过连接线添加 
 */
const addChildNodeToParent = (childNode, parentNode, addType) => {
  // 如果子节点已经在父节点的preIds中，则不需要添加
  const isAlreadyChild = childNode.preIds && childNode.preIds.includes(parentNode.nodeId);
  if (isAlreadyChild) return;
  if (addType === 'drag') {
    // 断开与原父节点的关系
    if (childNode.preIds && Array.isArray(childNode.preIds)) {
      // 遍历所有原父节点
      for (const oldParentId of childNode.preIds) {
        const oldParentNode = treeData.value.find(n => n.nodeId === oldParentId);
        if (oldParentNode && oldParentNode.nextIds) {
          // 从原父节点的nextIds中移除该子节点
          const index = oldParentNode.nextIds.indexOf(childNode.nodeId);
          if (index !== -1) {
            oldParentNode.nextIds.splice(index, 1);
          }
        }
      }
    }
    // 清空子节点的preIds并添加新的父节点
    childNode.preIds = [parentNode.nodeId];
    childNode.x = parentNode.x + Math.random() * 300;
    childNode.y = parentNode.y + 100;

  }
  else if (addType === 'connectLine') {
    if (!childNode.preIds.includes(parentNode.nodeId)) {
      childNode.preIds.push(parentNode.nodeId);
    }
  }

  // 确保父节点的nextIds中包含该子节点
  if (!parentNode.nextIds.includes(childNode.nodeId)) {
    parentNode.nextIds.push(childNode.nodeId);
  }
  // 更新子节点的层级
  updateNodeHierarchy(childNode, parentNode.level + 1);
  // 触发重新渲染
  treeData.value = [...treeData.value];
}

//  连线删除
const removeSelectedConnection = () => {
  if (!isEditMode.value) return;
  if (!selectedConnection.value) return;

  // 如果是父子节点之间的连接线
  if (selectedConnection.value.parentId && selectedConnection.value.childId) {
    const parentNode = treeData.value.find(node => node.nodeId === selectedConnection.value.parentId);
    const childNode = treeData.value.find(node => node.nodeId === selectedConnection.value.childId);

    if (parentNode && childNode && childNode.preIds) {
      const parentIdIndex = childNode.preIds.indexOf(parentNode.nodeId);
      if (parentIdIndex !== -1) {
        childNode.preIds.splice(parentIdIndex, 1);
      }
      if (parentNode.nextIds) {
        const childIdIndex = parentNode.nextIds.indexOf(childNode.nodeId);
        if (childIdIndex !== -1) {
          parentNode.nextIds.splice(childIdIndex, 1);
        }
      }

      // 如果子节点没有父节点了，则设置为根节点层级
      if (childNode.preIds.length === 0) {
        updateNodeHierarchy(childNode, 0);
      }

      connectionPositions.value.delete(`${selectedConnection.value.parentId}-${selectedConnection.value.childId}-midX`);
      connectionPositions.value.delete(`${selectedConnection.value.parentId}-${selectedConnection.value.childId}-midY`);
    }
  }

  // 取消选中连接线
  selectedConnection.value = null;
  hideContextMenu();
}

/**
 * 切换连接线方向
 * @param connection 连接线数据
 */
const toggleConnectionDirection = (direction) => {
  if (!isEditMode.value) return;
  if (!selectedConnection.value) return;
  // 生成一个唯一的键来存储连接方向偏好
  const directionKey = `${selectedConnection.value.parentId}-${selectedConnection.value.childId}-direction`;
  // 保存新的方向偏好
  connectionPositions.value.set(directionKey, direction);
  treeData.value = [...treeData.value];
  hideContextMenu();
}

const selectNode = (node) => {
  // 保持概要节点的判断
  if (selectionBox.value.selectedNodes.length === 0) {
    selectedNode.value = node;
  }
  selectedConnection.value = null;
  nodeDrag.value.initialNodeX = node.x;
  nodeDrag.value.initialNodeY = node.y;
  hideAllMenu()
}

/**
 * 选择连接线
 * @param connection 连接线数据
 */
const selectConnection = (connection) => {
  selectedConnection.value = connection;
  hideAllMenu()
}

const handleSvgClick = (event) => {
  if (event.target !== svgRef.value && event.target !== canvasContainerRef.value) return
    selectedNode.value = null;
    selectedConnection.value = null;
    hideAllMenu()
}

// ======================节点拖拽=============
const handleNodeMouseDown = (node, event) => {
  if (event.button === 0) { // 左键
    selectNode(node);
    startDrag(event, node);
  }
}

const startDrag = (event, node) => {
  if (!isEditMode.value) return;
  // 确保只有在节点上点击才开始节点拖拽
  if (node) {
    nodeDrag.value.isDragging = true;
    nodeDrag.value.dragStartX = event.clientX;
    nodeDrag.value.dragStartY = event.clientY;

    // 添加全局鼠标事件监听器
    document.addEventListener('mousemove', handleNodeDragMouseMove);
    document.addEventListener('mouseup', handleNodeDragMouseUp);
  }
}

const handleNodeDragMouseMove = (event) => {
  // 获取画布容器的滚动偏移量
  const scrollLeft = canvasContainerRef.value?.scrollLeft || 0;
  const scrollTop = canvasContainerRef.value?.scrollTop || 0;
  
  // 计算鼠标移动距离，考虑滚动偏移量
  const dx = (event.clientX - nodeDrag.value.dragStartX) + scrollLeft - (canvasContainerRef.value?.scrollLeft || 0);
  const dy = (event.clientY - nodeDrag.value.dragStartY) + scrollTop - (canvasContainerRef.value?.scrollTop || 0);
  
  // 多选节点拖拽（通过框选实现）
  if (nodeDrag.value.isDragging && selectionBox.value.selectedNodes.length > 0) {
    selectionBox.value.selectedNodes.forEach(node => {
      let newNode = visibleNodes.value.find(n => n.nodeId === node.nodeId);
      if (!newNode) return;
      // 更新节点位置
      newNode.x = node.x + dx
      newNode.y = node.y + dy
      checkAndMountNode(node);
    })
    return
  }
  // 单个节点拖拽
  if (nodeDrag.value.isDragging && selectedNode.value) {
    selectedNode.value.x = nodeDrag.value.initialNodeX + dx;
    selectedNode.value.y = nodeDrag.value.initialNodeY + dy;

    if (selectedNode.value.y < 10 || selectedNode.value.x < 10) {
      selectedNode.value.y = selectedNode.value.y < 10 ? 12 : selectedNode.value.y
      selectedNode.value.x = selectedNode.value.x < 10 ? 12 : selectedNode.value.x
      handleNodeDragMouseUp()
    }
    checkAndMountNode(selectedNode.value);
  }
}

const handleNodeDragMouseUp = () => {
  nodeDrag.value.isDragging = false;
  clearSelectionBox()
  document.removeEventListener('mousemove', handleNodeDragMouseMove);
  document.removeEventListener('mouseup', handleNodeDragMouseUp);
  checkAndMountNode(selectedNode.value);

}
// ===============================拖拽节点挂载关系============================
const dragActiveNode = ref(null)   // 拖拽节点是否有目标节点
/**
 * 检查节点是否与其它节点重叠，如果重叠则挂载到该节点上
 * @param {Object} draggedNode 被拖拽的节点
 */
const checkAndMountNode = (draggedNode) => {
  if (!draggedNode) return
  // 获取被拖拽节点的实际尺寸
  const { nodeActualWidth: draggedNodeWidth, nodeActualHeight: draggedNodeHeight } = getActualData(draggedNode);
  const draggedNodeCenterX = draggedNode.x + draggedNodeWidth / 2;
  const draggedNodeCenterY = draggedNode.y + draggedNodeHeight / 2;

  // 查找是否有节点与被拖拽节点重叠
  for (const targetNode of treeData.value) {
    if (targetNode.nodeId === draggedNode.nodeId) continue;
    const { nodeActualWidth: targetNodeWidth, nodeActualHeight: targetNodeHeight } = getActualData(targetNode);
    // 计算目标节点的边界
    const targetNodeLeft = targetNode.x;
    const targetNodeRight = targetNode.x + targetNodeWidth;
    const targetNodeTop = targetNode.y;
    const targetNodeBottom = targetNode.y + targetNodeHeight;
    // 检查被拖拽节点的中心点是否在目标节点的范围内
    if (draggedNodeCenterX >= targetNodeLeft &&
      draggedNodeCenterX <= targetNodeRight &&
      draggedNodeCenterY >= targetNodeTop &&
      draggedNodeCenterY <= targetNodeBottom) {

      // 检查是否已经是父子关系
      const isAlreadyChild = (draggedNode.preIds && draggedNode.preIds.includes(targetNode.nodeId)) ||
        (targetNode.nextIds && targetNode.nextIds.includes(draggedNode.nodeId));

      // 如果不是父子关系，且目标节点不是被拖拽节点的子节点
      const isTargetChildOfDragged = isNodeChildOf(draggedNode, targetNode);

      if (!isAlreadyChild && !isTargetChildOfDragged) {
        dragActiveNode.value = targetNode
        // 将被拖拽节点挂载到目标节点上
        if (!nodeDrag.value.isDragging) {
          addChildNodeToParent(draggedNode, targetNode, 'drag');
          dragActiveNode.value = null
        }
        break;
      }
    }

    dragActiveNode.value = null
  }
}

/**
 * 检查一个节点是否是另一个节点的子节点（递归检查）
 * @param {Object} parentNode 父节点
 * @param {Object} childNode 子节点
 * @returns {Boolean} 是否是子节点
 */
const isNodeChildOf = (parentNode, childNode) => {
  if (!parentNode.nextIds || parentNode.nextIds.length === 0) {
    return false;
  }

  if (parentNode.nextIds.includes(childNode.nodeId)) {
    return true;
  }

  // 递归检查子节点的子节点
  for (const nextId of parentNode.nextIds) {
    const nextNode = treeData.value.find(node => node.nodeId === nextId);
    if (nextNode && isNodeChildOf(nextNode, childNode)) {
      return true;
    }
  }

  return false;
}

// 双击节点进行编辑
const handleNodeDoubleClick = (node, event) => {
  if (!isEditMode.value) return;
  event.preventDefault()
  contextEditor.value.node = node
  contextEditor.value.x = event.clientX;
  contextEditor.value.y = event.clientY;
  editNodeFromContextMenu()
  setTimeout(() => {
    textInput.value.focus();
    textInput.value.select();
  }, 100)
}

/**
 * 右键菜单事件
 * @param menuType 菜单类型
 * @param node 节点
 * @param event 
 */
const showContextMenu = (menuType, node, event) => {
  if (!isEditMode.value) return;
  event.preventDefault()
  contextMenu.value.visible = false;
  // 设置新的菜单信息
  contextMenu.value.menuType = menuType
  contextMenu.value.x = event.clientX;
  contextMenu.value.y = event.clientY;

  contextEditor.value.x = event.clientX;
  contextEditor.value.y = event.clientY;

  if (menuType === 'path') {
    selectedConnection.value = node
  }
  else if (menuType === 'node') {
    contextMenu.value.node = node;
    contextEditor.value.node = node;
    selectedNode.value = node
  }
  else if (menuType === 'add') {
    selectedNode.value = null
  }
  contextMenu.value.visible = true;
  event.preventDefault();
}

// 编辑
const editNodeFromContextMenu = () => {
  if (contextEditor.value.node) {
    contextEditor.value.visible = true
    contextEditor.value.editingNodeContent = contextEditor.value.node.name
    hideContextMenu();
  }
}

// 保存节点内容
const saveNodeContent = () => {
  if (selectedNode.value) {
    selectedNode.value.name = contextEditor.value.editingNodeContent
    hideEditor()
    updateConnectionPoints()
  }
}

// 更新连接点位置
const updateConnectionPoints = () => {
  // 当节点内容改变时，重新计算连接点位置
  nextTick(() => {
    treeData.value = [...treeData.value]
  })
}

// 删除
const removeNodeFromContextMenu = () => {
  if (selectedNode.value && selectedNode.value.level === 0) return
  if (selectedNode.value && selectedNode.value.nodeId !== 1) {
    removeSelectedNode();
    hideAllMenu();
  }
}

// 折叠/展开节点=========================
const toggleNodeCollapseFromContextMenu = () => {
  if (!selectedNode.value) return
  const nodeId = selectedNode.value.nodeId;
  if (collapsedNodes.value.has(nodeId)) {
    collapsedNodes.value.delete(nodeId);
  } else {
    collapsedNodes.value.add(nodeId);
  }
  hideAllMenu();
};

const hideAllMenu = () => {
  hideContextMenu()
  hideEditor()
}

const hideContextMenu = () => {
  contextMenu.value.visible = false;
  contextMenu.value.node = null;
  contextMenu.value.otherMenu = false;
  selectedConnection.value = null
}
const hideEditor = () => {
  contextEditor.value.visible = false;
  contextEditor.value.node = null;
  contextEditor.value.editingNodeContent = null
}

// 处理画布鼠标按下事件
const handleCanvasMouseDown = (event) =>{
  if (isEditMode.value){
    // 框选功能
    handleCanvasSelectFrame(event)
  }
  else{
    // 画布拖拽 
    handlePanDrag(event)
  }
}

// =================画布拖拽   只有在点击SVG背景（非节点、连接线等元素）时才启用画布拖拽
// 画布拖拽相关变量
const panDrag = ref({
  isPanning: false,
  startPanX: 0,
  startPanY: 0,
  startScrollLeft: 0,
  startScrollTop: 0,
})

const handlePanDrag = (event) => {
  // 确保没有节点被选中时才允许画布拖拽
  if ((event.target === svgRef.value || event.target === canvasContainerRef.value) && !selectedNode.value) {
    panDrag.value.isPanning = true;
    panDrag.value.startPanX = event.clientX;
    panDrag.value.startPanY = event.clientY;
    panDrag.value.startScrollLeft = canvasContainerRef.value.scrollLeft;
    panDrag.value.startScrollTop = canvasContainerRef.value.scrollTop;
    // 添加全局鼠标事件监听器
    document.addEventListener('mousemove', handlePanMouseMove);
    document.addEventListener('mouseup', handlePanMouseUp);
    event.preventDefault();
  };
};

const handlePanMouseMove = (event) => {
  if (panDrag.value.isPanning && canvasContainerRef.value) {
    const dx = event.clientX - panDrag.value.startPanX;
    const dy = event.clientY - panDrag.value.startPanY;

    canvasContainerRef.value.scrollLeft = panDrag.value.startScrollLeft - dx;
    canvasContainerRef.value.scrollTop = panDrag.value.startScrollTop - dy;
  }
};

const handlePanMouseUp = () => {
  panDrag.value.isPanning = false;
  // 移除全局鼠标事件监听器
  document.removeEventListener('mousemove', handlePanMouseMove);
  document.removeEventListener('mouseup', handlePanMouseUp);
};

// ================================框选功能相关方法======================================

const handleCanvasSelectFrame = (event) => {
  // 只有在框选模式下并且点击的是画布（不是节点）时才开始框选
  if (event.target !== svgRef.value && event.target !== canvasContainerRef.value) return

    event.preventDefault();
    const { x, y } = getMousePositionInCanvas(event);
    
    selectionBox.value = {
      visible: true,
      selectedNodes: [],
      startX: x,
      startY: y,
      endX: x,
      endY: y,
      width: 0,
      height: 0
    };

    // 添加鼠标移动和松开事件监听器
    document.addEventListener('mousemove', handleCanvasMouseMove);
    document.addEventListener('mouseup', handleCanvasMouseUp);
};

// 处理画布鼠标移动事件
const handleCanvasMouseMove = (event) => {
  if (selectionBox.value.visible) {
    const { x, y } = getMousePositionInCanvas(event);
    selectionBox.value.endX = x;
    selectionBox.value.endY = y;
    // 计算宽度和高度（可能为负数）
    selectionBox.value.width = Math.abs(x - selectionBox.value.startX);
    selectionBox.value.height = Math.abs(y - selectionBox.value.startY);
    
    // 添加自动滚动功能
    autoScrollCanvas(event);
  }
};

// 自动滚动画布功能
const autoScrollCanvas = (event) => {
  if (!canvasContainerRef.value) return;
  const rect = canvasContainerRef.value.getBoundingClientRect();
  const edgeThreshold = 50; // 边缘阈值，单位px
  
  const mouseX = event.clientX - rect.left;
  const mouseY = event.clientY - rect.top;
  
  // 水平滚动
  if (mouseX < edgeThreshold) {
    // 靠近左边缘，向左滚动
    canvasContainerRef.value.scrollLeft -= 10;
  } else if (mouseX > rect.width - edgeThreshold) {
    // 靠近右边缘，向右滚动
    canvasContainerRef.value.scrollLeft += 10;
  }
  
  // 垂直滚动
  if (mouseY < edgeThreshold) {
    // 靠近上边缘，向上滚动
    canvasContainerRef.value.scrollTop -= 10;
  } else if (mouseY > rect.height - edgeThreshold) {
    // 靠近下边缘，向下滚动
    canvasContainerRef.value.scrollTop += 10;
  }
};

// 处理画布鼠标松开事件
const handleCanvasMouseUp = () => {
  if (selectionBox.value.visible) {
    document.removeEventListener('mousemove', handleCanvasMouseMove);
    document.removeEventListener('mouseup', handleCanvasMouseUp);
    // 选择区域内的节点
    selectNodesInBox();
    selectionBox.value.visible = false
  }
};

// 清除框选区域显示
const clearSelectionBox = () => {
  if(selectionBox.value.selectedNodes.length == 0) return
  selectionBox.value = {
    visible: false,
    selectedNodes: [],
    startX: 0,
    startY: 0,
    endX: 0,
    endY: 0,
    width: 0,
    height: 0
  };
};

// 选择区域内的节点
const selectNodesInBox = () => {
  const minX = Math.min(selectionBox.value.startX, selectionBox.value.endX);
  const maxX = Math.max(selectionBox.value.startX, selectionBox.value.endX);
  const minY = Math.min(selectionBox.value.startY, selectionBox.value.endY);
  const maxY = Math.max(selectionBox.value.startY, selectionBox.value.endY);
  selectionBox.value.selectedNodes = [];

  // 遍历所有可见节点，检查是否在框选区域内
  visibleNodes.value.forEach(node => {
    const { nodeActualWidth, nodeActualHeight } = getActualData(node);
    const nodeRight = node.x + nodeActualWidth;
    const nodeBottom = node.y + nodeActualHeight;

    // 检查节点是否完全在框选区域内（完全包含）
    if (node.x >= minX && nodeRight <= maxX && node.y >= minY && nodeBottom <= maxY) {
      selectionBox.value.selectedNodes.push({ ...node });
    }
  });
  if (selectionBox.value.selectedNodes.length === 0) {
    clearSelectionBox();
  }
};

// =======================概要节点==========================
const handleProfile = () => {
  if (selectionBox.value.selectedNodes.length === 0) return
  const lastSelectedNode = selectionBox.value.selectedNodes[selectionBox.value.selectedNodes.length - 1];

  const newNode = {
    nodeId: uuidv4(),
    level: lastSelectedNode.level + 1,
    preIds: [],
    nextIds: [],
    name: `概要节点`,
    x: lastSelectedNode.x + 150,
    y: lastSelectedNode.y + Math.random() * 100 - 50,
    style: NODE_STYLE
  };

  // 将新节点添加到选中节点的子节点中
  selectionBox.value.selectedNodes.forEach(selectedNode => {
    if (!selectedNode.nextIds.includes(newNode.nodeId)) {
      selectedNode.nextIds.push(newNode.nodeId);
    }

    if (!newNode.preIds.includes(selectedNode.nodeId)) {
      newNode.preIds.push(selectedNode.nodeId);
    }
  });
  treeData.value.push(newNode);
  clearSelectionBox();
};

/**
 * 更新节点及其子节点的层级
 * @param node 需要更新的节点
 * @param newHierarchy 新的层级
 */
const updateNodeHierarchy = (node, newHierarchy) => {
  node.level = newHierarchy;

  // 递归更新所有子节点的层级
  if (node.nextIds && node.nextIds.length > 0) {
    node.nextIds.forEach(childId => {
      const childNode = treeData.value.find(n => n.nodeId === childId);
      if (childNode) {
        updateNodeHierarchy(childNode, newHierarchy + 1);
      }
    });
  }
}

// ====================================数据的绘制,保存与重置==========================
// 数据保存,还原坐标
const saveData = () => {
  clearSelectionBox()
  localStorage.setItem('MINDDATA',JSON.stringify(treeData.value))
}

const reshData = () => {
  clearSelectionBox()
  // 获取内存数据
  const data =  localStorage.getItem('MINDDATA')
  treeData.value = JSON.parse(data)
}

// 编辑模式切换
const toggleEditMode = () => {
  isEditMode.value = !isEditMode.value;
  if (!isEditMode.value) {
    hideAllMenu();
    clearSelectionBox();
  }
}

const initData = () => {
  treeData.value = []
  oldData = []

  selectedNode.value = null
  selectedConnection.value = null
  connectionSource.value = null

  isEditMode.value = false
  isFullScreen.value = false
}
// =================================节点详情===================================
const detailRef = ref(null);
const drawer = ref(false)
const handleChange = () => {
  clearSelectionBox()
  drawer.value = !drawer.value
}
const updateNodeStyleEvent = (nodeStyleVal) => {
  if (!selectedNode.value) return
  updateConnectionPoints()
}

// 组件挂载时初始化鱼骨图
onMounted(async () => {
  const data =  localStorage.getItem('MINDDATA')
  treeData.value = data ? JSON.parse(data) : fakeData
})

</script>

<style scoped lang="scss">
.mindMap {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  margin: auto;
  padding: 5px;

  .chart-mindMap {
    position: relative;
    box-sizing: border-box;
    // padding: 20px;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    width: 100%;
    height: 100%;
  }

  .edit-panel {
    box-sizing: border-box;
    display: flex;
    justify-content: space-between;
    padding: 5px 10px;
    .operate-btn {
        display: flex;
        gap: 10px;
      }

    .item-menu {
      display: flex;
      align-items: center;
      color: #696969;
    }
  }

  .canvas-container {
    flex: 1;
    box-sizing: border-box;
    position: relative;
    overflow: auto;
    width: 100%;
    height: 100%;
    min-height: 400px;
    background: #ffffff;
    border-radius: 10px;
    border: 1px solid #00000026;
    // box-shadow: 0 4px 20px #00000026;
    cursor: default;

    .svg-box {
      box-sizing: border-box;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      overflow: visible;
      background-color: #ffffff2a;
    }

    .connection {
      stroke: #7f8c8d;
      stroke-width: 2;
      fill: none;
      cursor: pointer;

      &:hover {
        stroke: #3498db;
        stroke-width: 3;
      }

      &.selected {
        stroke: #e74c3c;
        stroke-width: 3;
      }
    }

    .control-point {
      cursor: crosshair;
      opacity: 1;
      transition: opacity 0.2s ease;
    }

    .selection-box {
      pointer-events: none;
    }
  }

  .node {
    box-sizing: border-box;
    position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 5px;
    cursor: move;

    .node-main {
      box-sizing: border-box;
      padding: 0 10px;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;

      .node-text {
        max-width: 200px;
        word-wrap: break-word;
        user-select: none;
      }
    }

    .node-version-class {
      position: absolute;
      top: 2px;
      left: 2px;
      font-size: 11px;
      color: #fff;
      font-weight: bold;
      background-color: #ff1900;
      border-radius: 50%;
      padding: 0 2px;
      z-index: 15;
    }

    .plan-end-time {
      position: absolute;
      bottom: 0px;
      left: 1px;
      font-size: 10px;
      color: #a504b4a1;
    }

    .owner-name {
      position: absolute;
      bottom: 0px;
      right: 1px;
      font-size: 10px;
      color: #a504b4a1;
    }

    .progress-container {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: #53c41a33;
    }
  }

  .dragActiveNode {
    transition: all 0.5s;
    transform: scale(1.5);
    border: 2px solid black;
  }

  .collapsed-count {
    position: absolute;
    bottom: -20px;
    left: calc(50% - 10px);
    border: 2px solid;
    background-color: #ffffff;
    border-radius: 50%;
    width: 20px;
    height: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 12px;
    font-weight: bold;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  }

  .context-menu {
    position: fixed;
    background: white;
    border-radius: 5px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    z-index: 1000;
    width: 120px;

    .context-menu-item {
      box-sizing: border-box;
      position: relative;
      padding: 8px 12px;
      height: 40px;
      cursor: pointer;
      font-size: 14px;
      color: #333;
      border-bottom: 1px solid #eee;

      &:hover {
        background: #f5f5f5;
      }

      &:last-child {
        border-bottom: none;
      }

      &.disabled {
        color: #999;
        cursor: not-allowed;
      }

      &.disabled:hover {
        background: white;
      }
    }

    .context-menu-item-direction {
      background: white;
      position: absolute;
      width: 120px;
      border-radius: 5px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
      top: 0px;
      left: 120px;
    }
  }

  .context-editor {
    position: fixed;
    background: white;
    border-radius: 5px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    z-index: 1000;
    width: 200px;
  }

  .mode-indicator {
    position: absolute;
    top: 50px;
    left: 10px;
    padding: 5px 10px;
    color: white;
    border-radius: 4px;
    font-size: 12px;
    z-index: 4;

    &.edit-mode-indicator {
      background: #e74c3c;
    }

    &.view-mode-indicator {
      background: #3498db;
    }
  }
}
</style>